package com.css.devops.service.jenkins;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.css.devops.component.JenkinsBasicComponent;
import com.css.devops.constants.DevopsConstants;
import com.css.devops.domain.BuildMonitor;
import com.css.devops.domain.BuildResult;
import com.css.devops.domain.BuildState;
import com.css.devops.domain.JobStatistics;
import com.css.devops.domain.PageResult;
import com.css.devops.domain.PageUtil;
import com.css.devops.domain.vo.BuildMonitorQueryCriteria;
import com.css.devops.service.DevopsBuildMonitor;
import com.css.devops.utils.JsonMapperUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Lists;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpResponse;
import lombok.extern.slf4j.Slf4j;

/**
 * 根据构建id获取构建阶段信息
 */
@Slf4j
@Service("jenkinsBuildMonitorService")
public class JenkinsBuildMonitorService implements DevopsBuildMonitor {

	@Autowired
	private JenkinsBasicComponent jenkinsBasicComponent;
	
	/**
	 * 根据pipeline的id获取构建过程中的各个阶段
	 * @param buildMonitorQueryCriteria
	 * @return
	 */
    @Override
	public PageResult<BuildMonitor> queryBuildMonitor(BuildMonitorQueryCriteria buildMonitorQueryCriteria) {
    	PageResult<BuildMonitor> pageResult = null;
        try {
            String endpoint = String.format(DevopsConstants.JENKINS_MONITOR_ENDPOINT, buildMonitorQueryCriteria.getPipeline(), buildMonitorQueryCriteria.getStart(), buildMonitorQueryCriteria.getEnd());
            HttpResponse response = jenkinsBasicComponent.getRequest(endpoint);
            
            if (response.getStatus() == HttpStatus.OK.value()) {
            	List<BuildMonitor> buildMonitors = Lists.newArrayList();
                JsonNode builds = JsonMapperUtils.getInstance().readTree(response.body());
                builds.forEach(node->{
                	BuildMonitor buildMonitor = buildMonitor(node);
                    buildMonitors.add(buildMonitor);
                });
                pageResult = PageUtil.toPage(buildMonitors, getTotalNumber(buildMonitorQueryCriteria));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return pageResult;
    }
    
    /**
     * 获取job构建的总数
     * @param buildMonitorQueryCriteria
     * @return
     */
    private Integer getTotalNumber(BuildMonitorQueryCriteria buildMonitorQueryCriteria) {
    	Integer totalNumber = 0;
    	try {
            String endpoint = String.format(DevopsConstants.JENKINS_MONITOR_ENDPOINT, buildMonitorQueryCriteria.getPipeline(), buildMonitorQueryCriteria.getStart(), DevopsConstants.MAX_LIMIT);
            HttpResponse response = jenkinsBasicComponent.getRequest(endpoint);
            
            if (response.getStatus() == HttpStatus.OK.value()) {
                JsonNode builds = JsonMapperUtils.getInstance().readTree(response.body());
                totalNumber = builds.size();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    	return totalNumber;
    }
    
    /**
     * 统计job任务的信息
     * @param jobName
     * @return
     */
    public JobStatistics statisticsJob(String jobName) {
    	JobStatistics jobStatistics = new JobStatistics();
    	BuildMonitorQueryCriteria buildMonitorQueryCriteria = new BuildMonitorQueryCriteria();
		buildMonitorQueryCriteria.setPipeline(jobName);
		buildMonitorQueryCriteria.setStart(0);
		buildMonitorQueryCriteria.setEnd(DevopsConstants.MAX_LIMIT);
		PageResult<BuildMonitor> pageResult = queryBuildMonitor(buildMonitorQueryCriteria);
		if(Objects.nonNull(pageResult) && !CollectionUtils.isEmpty(pageResult.getContent())) {
			List<BuildMonitor> buildMonitors = pageResult.getContent();
			jobStatistics.setTotal(buildMonitors.size());
			jobStatistics.setSuccess(buildMonitors.stream().filter(p->p.getResult().getCode().equals(BuildResult.SUCCESS.getCode())).collect(Collectors.toList()).size());
			jobStatistics.setFailure(buildMonitors.stream().filter(p->p.getResult().getCode().equals(BuildResult.FAILURE.getCode())).collect(Collectors.toList()).size());
			jobStatistics.setAborted(buildMonitors.stream().filter(p->p.getResult().getCode().equals(BuildResult.FAILURE.getCode())).collect(Collectors.toList()).size());
			jobStatistics.setUnknown(buildMonitors.stream().filter(p->p.getResult().getCode().equals(BuildResult.UNKNOWN.getCode())).collect(Collectors.toList()).size());
		}
		return jobStatistics;
    }
    
    /**
     * 根据JsonNode 构建 BuildMonitor
     * @param node
     * @return
     */
    @Override
	public BuildMonitor buildMonitor(JsonNode node) {
    	BuildMonitor buildMonitor = new BuildMonitor();
        String id = node.path("id").asText();
        String branchName = node.path("pipeline").asText();
        String startTime = node.path("startTime").asText();
        String endTime = node.path("endTime").asText();
        String result = node.path("result").asText();
        String state = node.path("state").asText();
        long durationInMillis = node.path("durationInMillis").asLong();
        String runSummary = node.path("runSummary").asText();
        String cause = node.path("causes").get(0).path("shortDescription").asText();
        String msg = node.path("changeSet").isEmpty()? StringUtils.EMPTY : node.path("changeSet").get(0).path("msg").asText();
        String commitId = node.path("commitId").asText();
        String userName = node.path("causes").get(0).path("userName").asText();
        
        buildMonitor.setId(id);
        buildMonitor.setBranchName(branchName);
        buildMonitor.setStartTime(DateUtil.parse(startTime));
        buildMonitor.setEndTime(DateUtil.parse(endTime));
        buildMonitor.setResult(BuildResult.getBuildResult(result));
        buildMonitor.setDuration(durationInMillis);
        buildMonitor.setCause(cause);
        buildMonitor.setMsg(msg);
        buildMonitor.setSummary(runSummary);
        buildMonitor.setState(BuildState.getBuildState(state));
        buildMonitor.setUserName(userName);
        buildMonitor.setCommitId(commitId);
        return buildMonitor;
    }
}
